#include "Common.h"
#include "ExampleGame.h"
#include "Engine.h"
#include "SceneManager.h"
#include "Scene.h"
#include "SceneNode.h"
#include "BoxShape.h"
#include "Entity.h"
#include "Camera.h"
#include "InputBoxGhost.h"
#include "InputBoxFPS.h"
#include "LocalPlayer.h"
#include "LoginWindow.h"
#include "Skeleton.h"
#include <windows.h>
#include <sstream>


ExampleGame::ExampleGame()
	: mInputBox(NULL)
	, mCamera(NULL)
	, mPlayer(NULL)
	, mStartPoint(0, 180, -300)
{
	Engine::NewInstance();
	Engine::Instance().setGame(this);
}

ExampleGame::~ExampleGame()
{
	Engine::DeleteInstance();
}

bool ExampleGame::Init()
{
	if (!Engine::Instance().Init())
		return false;

	LoginWindow::Instance().Open();

	mInputBox = new InputBoxGhost();
	mInputBox->setPosition(mStartPoint);

	CreateScene();

	return true;
}

void ExampleGame::Start()
{
	Engine::Instance().Start();
}

void ExampleGame::Exit()
{
	SAFE_DELETE(mInputBox);
	SAFE_DELETE(mPlayer);

	Engine::Instance().Exit();
}

int GetUniqueID()
{
	static int UniqueID = 12;
	return UniqueID++;
}

void AddObject(Scene* scene, BYTE Type, const Vector3& Scale, const Vector3& Position, const Rotator& Rotation, const Vector4& Color)
{
	std::stringstream ss;
	ss << GetUniqueID();
	std::string name = "Sharpe_" + ss.str();

	SceneNode* node = scene->createSceneNode(name);
	node->setScale(Scale);
	node->setPosition(Position);
	node->setRotation(Rotation);

	Shape* shape = scene->Create<BoxShape>(name);
	shape->setDiffuse(Color);

	node->Attach(shape);
}

void AddTestMesh(Scene* scene, const std::string& mesh, const Vector3& Scale, const Vector3& Position, const Rotator& Rotation)
{
	std::stringstream ss;
	ss << GetUniqueID();
	std::string name = "Mesh_" + ss.str();
	
	NameValeParamMap params;
	params["mesh"] = mesh;
	Entity* entity = scene->Create<Entity>(name, &params);
	if (entity == NULL)
		return;

	if (entity->getSkeletonInstance() && entity->getSkeletonInstance()->EnableAnim("p_m_run"))
		scene->CreateUpdater(entity);

	SceneNode* node = scene->createSceneNode(name);
	node->setScale(Scale);
	node->setPosition(Position);
	node->setRotation(Rotation);

	node->Attach(entity);
}

void ExampleGame::CreateScene()
{
	SceneManager* sceneMgr = Engine::Instance().getSceneManager();
	Scene* scene = sceneMgr->getScene();

	struct SimpleSceneData
	{
		BYTE Type;
		Vector3 Scale;
		Vector3 Position;
		Rotator Rotation;
		Vector4 Color;
	};

	SimpleSceneData objects[] = {
		{1, Vector3(100, 0.1f, 100), Vector3(-50 * 100, 0,  -50 * 100), Rotator::Identity, Vector4(0.1f, 0.0f, 0.8f)},
		{1, Vector3(1), Vector3(0, 50, 0), Rotator(500, 3000, 200), Vector4(0.1f, 0.9f, 0.8f)},
		
		// box
		{1, Vector3(100, 10, 1), Vector3(-50 * 100, 0,  50 * 100), Rotator::Identity, Vector4(0.8f, 0.8f, 0.8f)},
		{1, Vector3(100, 10, 1), Vector3(-50 * 100, 0, -50 * 100), Rotator::Identity, Vector4(0.8f, 0.8f, 0.8f)},
		{1, Vector3(1, 10, 100), Vector3(+50 * 100, 0, -50 * 100), Rotator::Identity, Vector4(0.8f, 0.8f, 0.8f)},
		{1, Vector3(1, 10, 100), Vector3(-50 * 100, 0, -50 * 100), Rotator::Identity, Vector4(0.8f, 0.8f, 0.8f)},
	};

	for (int i = 0; i < sizeof(objects) / sizeof(objects[0]); i++)
	{
		SimpleSceneData& data = objects[i];
		AddObject(scene, data.Type,
			data.Scale,
			data.Position,
			data.Rotation,
			data.Color);
	}

	AddTestMesh(scene, "111.mesh", Vector3(1), Vector3(-300, 0, 200), Rotator::Identity);
	AddTestMesh(scene, "222.mesh", Vector3(1), Vector3(-100, 0, 200), Rotator::Identity);
	AddTestMesh(scene, "testC04.mesh", Vector3(1), Vector3( 100, 0, 200), Rotator::Identity);
	AddTestMesh(scene, "testC04.mesh", Vector3(1), Vector3( 300, 0, 200), Rotator::Identity);

	// setup camera.
	mCamera = Engine::Instance().getCamera();
	mCamera->setPosition(mStartPoint);
}

void ExampleGame::CreatePlayer()
{
	SceneManager* sceneMgr = Engine::Instance().getSceneManager();
	Scene* scene = sceneMgr->getScene();

	// create a player in the scene.
	SAFE_DELETE(mPlayer);
	mPlayer = new LocalPlayer();
	mPlayer->setPosition(mStartPoint);
	mPlayer->AddToMap(scene);
	
	SAFE_DELETE(mInputBox);
	mInputBox = new InputBoxFPS(mPlayer);
}

void ExampleGame::AddBoxHere(int count)
{
	SceneManager* sceneMgr = Engine::Instance().getSceneManager();
	Scene* scene = sceneMgr->getScene();

	for (int i = 0; i < count; i++)
	{
		AddObject(scene, 1,
			Vector3(1),
			mCamera->getPosition() + mCamera->getRotation().Quat() * Vector3(0, 0, 200) + Vector3(Math::UnitRadom(), Math::UnitRadom(), Math::UnitRadom()) * 200 ,
			Rotator(
				Math::Trunc(Math::UnitRadom() * 10000),
				Math::Trunc(Math::UnitRadom() * 10000),
				Math::Trunc(Math::UnitRadom() * 10000)),
			Vector4(Math::UnitRadom(), Math::UnitRadom(), Math::UnitRadom(), 1));
	}
}

void ExampleGame::StartGame()
{
	CreatePlayer();
}

void ExampleGame::Update(float elapsedTime)
{
	if (mPlayer != NULL)
		mPlayer->Update(elapsedTime);

	// the move/rotate only happend immediate mode.
	if (InputManager::Instance().getImmediateMode())
	{
		if (mInputBox)
		{
			mInputBox->Update(elapsedTime);

			mCamera->setPosition(mInputBox->getPosition());
			mCamera->setRotation(mInputBox->getRotation());
		}
	}
}